package client

import (
	"encoding/json"
	"fmt"
	"github.com/antchfx/htmlquery"
	"github.com/gorilla/mux"
	"github.com/nats-io/nats-server/v2/server"
	"github.com/nats-io/nats.go"
	"golang.org/x/net/html"
	"io/ioutil"
	"net/http"
	"strings"
	"time"
)

type Message struct {
	Event     string              `json:"event"`
	Affiliate string              `json:"affiliate"`
	Params    map[string][]string `json:"params"`
}
type AndroidAppInfoResponse struct {
	Code    bool   `json:"code"`
	Updated string `json:"updated"`
	Version string `json:"version"`
	Size    string `json:"size"`
}
type IosAppInfoResponse struct {
	Code                      bool   `json:"code"`
	MinimumOsVersion          string `json:"minimumOsVersion"`
	FileSizeBytes             string `json:"fileSizeBytes"`
	TrackViewUrl              string `json:"trackViewUrl"`
	BundleId                  string `json:"bundleId"`
	TrackName                 string `json:"trackName"`
	CurrentVersionReleaseDate string `json:"currentVersionReleaseDate"`
	Currency                  string `json:"currency"`
	Version                   string `json:"version"`
	Description               string `json:"description"`
}
type AppleAppInfoContext struct {
	Result []IosAppInfoResponse `json:"results"`
}

var (
	nc *nats.Conn
)

func Start(s *server.Server) {
	r := mux.NewRouter()
	r.HandleFunc("/{event}/{affiliate}", httpHandler)
	r.HandleFunc("/appinfo", appInfoHandler)
	srv := &http.Server{
		Handler:      r,
		Addr:         "0.0.0.0:80",
		WriteTimeout: 15 * time.Second,
		ReadTimeout:  15 * time.Second,
	}

	_nc, err := nats.Connect(s.Addr().String())
	if err != nil {
		panic(err)
	}
	nc = _nc
	s.Logger().Noticef("Client is ready")
	s.Logger().Fatalf("%v", srv.ListenAndServe())
	nc.Close()
}

func httpHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	fmt.Printf("%v: event:%v, affiliate:%v, params:%v \n", r.Method, vars["event"], vars["affiliate"], r.URL.RawQuery)
	event, affiliate := vars["event"], vars["affiliate"]
	msg, err := json.Marshal(&Message{
		Event:     event,
		Affiliate: affiliate,
		Params:    r.URL.Query(),
	})
	if err != nil {
		fmt.Printf("error:%v \n", err.Error())
		w.WriteHeader(http.StatusBadRequest)
		_, _ = w.Write([]byte("error"))
		return
	}
	err = nc.Publish(event, msg)
	if err != nil {
		fmt.Printf("error:%v \n", err.Error())
		w.WriteHeader(http.StatusBadRequest)
		_, _ = w.Write([]byte("error"))
		return
	}
	w.WriteHeader(http.StatusOK)
	_, _ = w.Write([]byte("success"))
}

func appInfoHandler(w http.ResponseWriter, r *http.Request) {
	query := r.URL.Query()
	if !query.Has("platform") {
		w.WriteHeader(http.StatusBadRequest)
		_, _ = w.Write([]byte("error"))
		return
	}
	platform := strings.ToLower(query.Get("platform"))
	appInfo := []byte("")
	if platform == "android" {
		appInfo, _ = json.Marshal(getAndroidAppInfo(query.Get("appid"), query.Get("country")))
	} else if platform == "ios" {
		appInfo, _ = json.Marshal(getIosAppInfo(query.Get("appid"), query.Get("country")))
	} else {
		w.WriteHeader(http.StatusBadRequest)
		_, _ = w.Write([]byte("platform unSupport"))
		return
	}
	w.WriteHeader(http.StatusOK)
	_, _ = w.Write([]byte(appInfo))
}

func getNodeHtml(node *html.Node, expr string) string {
	nodes := htmlquery.Find(node, expr)
	if len(nodes) > 0 {
		node := nodes[0]
		return htmlquery.OutputHTML(node, false)
	}
	return ""
}

func getAndroidAppInfo(appid string, country string) AndroidAppInfoResponse {
	var result AndroidAppInfoResponse
	result.Code = false
	countryPart := ""
	if country != "" {
		countryPart = "&gl=" + strings.ToLower(country)
	}
	doc, err := htmlquery.LoadURL("https://play.google.com/store/apps/details?id=" + appid + countryPart)
	if err == nil {
		result.Code = true
		result.Updated = getNodeHtml(doc, "/html/body/div[1]/div[4]/c-wiz/div/div[2]/div/div/main/c-wiz[last()]/div[1]/div[2]/div/div[1]/span/div/span")
		result.Version = getNodeHtml(doc, "/html/body/div[1]/div[4]/c-wiz/div/div[2]/div/div/main/c-wiz[last()]/div[1]/div[2]/div/div[4]/span/div/span")
		result.Size = getNodeHtml(doc, "/html/body/div[1]/div[4]/c-wiz/div/div[2]/div/div/main/c-wiz[last()]/div[1]/div[2]/div/div[2]/span/div/span")
	}
	return result
}

func getIosAppInfo(appid string, country string) IosAppInfoResponse {
	var result IosAppInfoResponse
	result.Code = false
	countryPart := ""
	if country != "" {
		countryPart = strings.ToLower(country) + "/"
	}
	resp, err := http.Get("http://itunes.apple.com/" + countryPart + "lookup?id=" + appid)
	if err != nil {
		return result
	}
	if resp.StatusCode != http.StatusOK {
		return result
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return result
	}

	var context AppleAppInfoContext
	err = json.Unmarshal(body, &context)
	if err == nil && len(context.Result) > 0 {
		result = context.Result[0]
		result.Code = true
	}
	return result
}
